"""文件管理视图"""
import json
import requests
from django.shortcuts import render, HttpResponse, reverse
from django.http import JsonResponse
from web.forms.file import FileRepositoryModelForm, FileCheckModelForm
from web import models
from utils import cos
from django.views.decorators.csrf import csrf_exempt


def file(request, project_id):
    """根据url传入的参数 判断 是否是根目录 folder为空 则是根目录
    http://127.0.0.1:8000/manage/15/file/?folder=15
    """

    parent_obj = None  # 初始化父级对象
    form = FileRepositoryModelForm(request, parent_obj)
    # 获取folder
    folder_id = request.GET.get('folder', '')
    # 如果存在 父级id 则表示是下一级目录
    if folder_id.isdecimal():
        parent_obj = models.FileRepository.objects.filter(id=int(folder_id), project=request.tracer.project,
                                                          file_type=2).first()
    # 获取该项目和当前目录下所有的文件对象
    # 1.获取根目录下所有文件
    if not parent_obj:
        files_list = models.FileRepository.objects.filter(parent__isnull=True, project=request.tracer.project).order_by(
            '-file_type')
    else:
        # 2.获取非根目录下所有文件
        files_list = models.FileRepository.objects.filter(parent=parent_obj, project=request.tracer.project).order_by(
            '-file_type')
    """
    目录切换的路径导航显示 目录1>目录2>...
    定制一个存放每个目录对象的列表，当 parent存在时，向列表里增加到首位，并给parent重新赋值，直到parent为none
    """
    parent = parent_obj  # 父目录对象
    path_list = []  # 存放对象的列表
    while parent:
        path_list.insert(0, {'id': parent.id, 'name': parent.name})
        parent = parent.parent

    if request.method == 'POST':

        """根据fid 判断是新建还是编辑"""
        fid = request.POST.get('fid', '')
        folder_obj = None
        if fid.isdecimal():
            folder_obj = models.FileRepository.objects.filter(id=int(fid), project=request.tracer.project,
                                                              file_type=2).first()
        if folder_obj:
            # 编辑
            form = FileRepositoryModelForm(request, parent_obj, data=request.POST, instance=folder_obj)
        else:
            # 新建
            form = FileRepositoryModelForm(request, parent_obj, data=request.POST)
        if form.is_valid():
            # 对其他字段进行赋值
            form.instance.project = request.tracer.project
            form.instance.file_type = 2
            form.instance.update_user = request.tracer.user
            form.instance.parent = parent_obj  # 父级目录
            form.save()
            return JsonResponse({'status': True})
        return JsonResponse({'status': False, 'error': form.errors})
    return render(request, 'file/file.html', {'form': form,
                                              'file_list': files_list,
                                              'path_list': path_list,
                                              'folder_obj': parent_obj
                                              }, )


# 删除文件
def file_delete(request, project_id):
    # 级联删除 只删除数据库中的值
    fid = request.GET.get('fid')
    delete_obj = models.FileRepository.objects.filter(id=fid, project=request.tracer.project).first()
    if delete_obj.file_type == 1:  # 删除文件（数据库中文件删除，cos对象存储中删除，项目已使用的用量还回去）
        # 归还项目已使用的量
        file_size = delete_obj.file_size
        request.tracer.project.use_space -= file_size
        request.tracer.project.save()
        # cos对象存储中删除.传入cos的文件名
        from utils.cos import delete_cos_file
        delete_cos_file(request.tracer.project.region, request.tracer.project.bucket, delete_obj.key)
        # 数据库中删除
        delete_obj.delete()
        return JsonResponse({'status': True})
    else:
        # 在cos中 删除文件夹,以及文件夹下的文件，
        total_size = 0  # 需要删除文件的大小总和
        folder_list = [delete_obj, ]  # 初始化要删除的文件夹下面所有的文件夹的列表
        file_obj_key_list = []  # 初始化要删除文件夹下的文件对象列表

        for folder in folder_list:
            # 获取当前文件夹下所有的文件和文件夹
            child_list = models.FileRepository.objects.filter(parent=folder, project_id=project_id).order_by(
                '-file_type')
            # 判断是否是文件夹 或是 文件
            for child in child_list:
                if child.file_type == 2:
                    folder_list.append(child)  # 增加文件夹对象到列表
                else:
                    total_size += child.file_size
                    file_obj_key_list.append({'Key': child.key})  # 增加文件 在cos中的名字 到列表

        if file_obj_key_list:
            # cos 批量删除对象

            cos.delete_cos_objects(request.tracer.project.region, request.tracer.project.bucket, file_obj_key_list)

        if total_size:
            # 归还容量
            request.tracer.project.use_space -= total_size
            request.tracer.project.save()
        # 数据库级联删除
    delete_obj.delete()
    return JsonResponse({'status': True})


# 上传文件获取临时凭证
@csrf_exempt
def cos_credential(request, project_id):
    # 获取临时凭证，包含前端发来的文件字典
    file_list = json.loads(request.body.decode('utf-8'))  # [{'name':'file_name','size':'file_size'},{},..]
    # 当前项目允许使用最大空间（G）
    project_total_size = request.tracer.price_policy.per_project_size
    # 当前项目已使用的空间（B）
    current_used_space = request.tracer.project.use_space
    # 循环列表,限制单文件上传大小，限制上传超出总容量大小(B)

    # 多个文件长传的总大小（B）
    file_total_size = 0
    for item in file_list:
        # 超出单文件大小上传的限制
        if item['size'] > request.tracer.price_policy.per_file_size * 1024 * 1024:
            msg = "单个文件上传不得超过%sM,文件:%s已超出最大限制，请升级套餐" % (request.tracer.price_policy.per_file_size, item['name'])
            return JsonResponse({'status': False, 'error': msg})
        file_total_size += item['size']
    # 多文件上传加上已使用的如果超出总容量则不允许通过
    if file_total_size + current_used_space > project_total_size * 1024 * 1024 * 1024:
        return JsonResponse({'status': False, 'error': '超出总容量限制，请升级套餐'})
    res_dict = cos.get_cos_credential(request.tracer.project.bucket, request.tracer.project.region)
    return JsonResponse({'status': True, 'data': res_dict})


# 接收文件上传成功之后前端发回的数据
@csrf_exempt
def file_post(request, project_id):
    # print(request.POST)
    # 对字段进行校验
    form = FileCheckModelForm(request.POST)
    # 校验成功，将数据保存到数据库

    if form.is_valid():
        # form.instance.project = request.tracer.project
        # form.instance.file_type = 1
        # form.instance.update_user = request.tracer.user
        # form.save()
        # 通过modelform 存储的对象 无法通过get_display获取到choice的中文
        data_dict = form.cleaned_data
        data_dict.pop('etag')
        data_dict.update({'project': request.tracer.project,
                          'file_type': 1,
                          'update_user': request.tracer.user})
        instance = models.FileRepository.objects.create(**data_dict)

        # 添加成功之后，需要将项目的已使用空间更新
        request.tracer.project.use_space += data_dict.get('file_size')
        request.tracer.project.save()

        result = {
            'id': instance.id,
            'name': instance.name,
            # 'file_type': instance.get_file_type_display()
            'file_size': instance.file_size,
            'update_user': instance.update_user.username,
            'update_time': instance.update_datetime.strftime('%Y-%m%d %X'),
            # 下载文件的url，返回给前端，用来添加href的属性
            'download_url':reverse('download',kwargs={'project_id':project_id,'file_id':instance.id})
        }
        return JsonResponse({'status': True, 'data': result})
    return JsonResponse({'status': False, 'data': form.errors})


def download(request, project_id, file_id):
    # 1. 获取文件内容(二进制)
    # with open('xx.png',mode='rb') as f:
    #     data =f.read()
    """从 cos存储中获取文件内容"""
    file_obj = models.FileRepository.objects.filter(id=file_id, project_id=project_id).first()
    res = requests.get(file_obj.file_path)
    data = res.content
    response = HttpResponse(data)
    # 2.设置文件类型对应的响应头
    response['Content-Disposition'] = "attachment;filename=%s" % file_obj.name
    # 3.返回数据给浏览器

    return response
